package com.heaboy.mvc;

import com.heaboy.annotation.Controller;
import com.heaboy.annotation.RequestMapping;

import java.io.File;
import java.lang.annotation.Annotation;
import java.lang.ref.ReferenceQueue;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
import java.util.regex.Matcher;

/**
 * @author heaboy
 * mvc类
 */
public class HeaboyMvc {
    //最终目的就是构建这两个map
    private static HashMap<String, Map<String,Method>> map=new HashMap<>(); //<类上注解的值,<方法上注解的值,对应方法>>
    private static HashMap<String, Object> objMap=new HashMap<>(); //<类上加的注解值,类对象>

    /**
     *
     * @param classPath
     * @param methodPath
     */
    public static void exec(String classPath,String methodPath){
        if(objMap.get(classPath)==null){
            System.out.println("没有这个类 404");
        }else {
            if(map.get(classPath).get(methodPath)==null){
                System.out.println("没有这个方法 404");
            }else {
                try {
                    map.get(classPath).get(methodPath).invoke(objMap.get(classPath));//获得对应的方法然后去执行，作用到类对象上
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                } catch (InvocationTargetException e) {
                    e.printStackTrace();
                }
            }
        }

    }

    /**
     * 扫描类信息，目的：构建两个map
     * @param path
     * @param packageName
     */
    public static void scanner(String path, String packageName) {
        // 遍历指定路径下的所有文件，并获取类文件的完整路径列表
        List<String> paths = traverseFolder2(path);

        // 遍历获取到的类文件路径列表
        for (String p : paths) {
            p = p.substring(path.length() - 1);

            try {
                // 构建类的全限定名（包括包名）
                String className = packageName + "." + p.replaceAll(Matcher.quoteReplacement(File.separator), ".");
                // 移除文件扩展名（.class）
                String replace = className.replace(".class", "");
                // 使用系统类加载器加载类，获得类信息
                Class<?> cl = ClassLoader.getSystemClassLoader().loadClass(replace);

                // 检查类是否有@Controller注解
                if (isController(cl)) {
                    // 检查类是否有@RequestMapping注解
                    if (isRequestMapping(cl)) {
                        // 获取类上的@RequestMapping注解
                        RequestMapping requestMapping = getRequestMapping(cl);
                        // 检查映射中是否包含该路径（requestMapping的值），如果存在则抛出异常
                        if (map.containsKey(requestMapping.value())) {
                            throw new RuntimeException("类多注解值：" + requestMapping.value());
                        } else {
                            // 不存在则放入
                            map.put(requestMapping.value(), new HashMap<>());
                            objMap.put(requestMapping.value(), cl.newInstance());//value是当前类的对象
                        }

                        //以上是类的处理，接下来是方法的处理*****************************

                        // 获取类中定义的所有方法
                        Method[] declaredMethods = cl.getDeclaredMethods();
                        for (Method declaredMethod : declaredMethods) {
                            // 检查方法是否有@RequestMapping注解
                            if (isRequestMapping(declaredMethod)) {
                                // 获取方法上的@RequestMapping注解
                                RequestMapping mapping = getRequestMapping(declaredMethod);
                                // 检查映射中是否包含该路径（requestMapping的值），如果存在则抛出异常
                                if (map.get(requestMapping.value()).containsKey(mapping.value())) {
                                    throw new RuntimeException("方法多注解值：" + requestMapping.value());
                                } else {
                                    // 不存在则放入
                                    map.get(requestMapping.value()).put(mapping.value(), declaredMethod);
                                }
                            }
                        }
                    } else {
                        // 如果类没有@RequestMapping注解，则抛出异常
                        throw new RuntimeException("类无requestMapping");
                    }
                }
            } catch (ClassNotFoundException e) {
                // 如果类找不到，打印堆栈跟踪
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                // 如果类实例化时发生非法访问异常，打印堆栈跟踪
                e.printStackTrace();
            } catch (InstantiationException e) {
                // 如果类实例化时发生实例化异常，打印堆栈跟踪
                e.printStackTrace();
            }
        }
    }


    private static boolean isController(Class cl){
        Annotation annotation = cl.getAnnotation(Controller.class);
        if(annotation!=null){
            return  true;
        }
        return false;
    }
    private static boolean isRequestMapping(Class cl){
        Annotation annotation = cl.getAnnotation(RequestMapping.class);
        if(annotation!=null){
            return  true;
        }
        return false;
    }
    private  static boolean isRequestMapping(Method method){
        Annotation annotation = method.getAnnotation(RequestMapping.class);
        if(annotation!=null){
            return  true;
        }
        return false;
    }
    private static RequestMapping getRequestMapping(Class cl){
        Annotation annotation = cl.getAnnotation(RequestMapping.class);
        if(annotation instanceof  RequestMapping){
            return  (RequestMapping) annotation;
        }
        return null;
    }
    private static RequestMapping getRequestMapping(Method method){
        Annotation annotation = method.getAnnotation(RequestMapping.class);
        if(annotation instanceof  RequestMapping){
            return  (RequestMapping) annotation;
        }
        return null;
    }

    /**
     * 扫描path路径下的全部文件，将所有文件以全路径名的形式存储在classFiles里面
     * @param path
     * @return
     */
    private static List<String> traverseFolder2(String path) {
        File file = new File(path);
        List<String> classFiles=new ArrayList<>();//文件的绝对路径
        if (file.exists()) {
            LinkedList<File> list = new LinkedList<File>();//文件夹的列表
            File[] files = file.listFiles();
            for (File file2 : files) {
                if (file2.isDirectory()) {//如果是文件夹
                    list.add(file2);
                } else {
                    classFiles.add(file2.getAbsolutePath());//添加file2的绝对路径
                }
            }
            File temp_file;
            while (!list.isEmpty()) {//文件夹列表不为空
                temp_file = list.removeFirst();//移除并返回队列的头部元素（一个文件夹）
                files = temp_file.listFiles();//文件夹内所有文件
                for (File file2 : files) {
                    if (file2.isDirectory()) {
                        list.add(file2);
                    } else {
                        classFiles.add(file2.getAbsolutePath());
                    }
                }
            }
        } else {

        }

        return classFiles;
    }
}

